#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX 1024
#define ARGC 64
#define SEP " "//分隔符空格

//字符串切割函数
int split(char* commandstr, char* argv[])
{
    assert(commandstr);
    assert(argv);

    argv[0] = strtok(commandstr, SEP);//函数切割后返回第一个地址
    if(argv[0] == NULL)
    {
        return 1;
    }

    int i = 1;
    while(argv[i++] = strtok(NULL, SEP));//这一句等价于下面的一段代码
    //while(1)
    //{
    //        argv[i] = strtok(NULL, SEP);//NULL表示还是继续切割commandstr
    //        if(argv[i] == NULL)
    //        {
    //            break;
    //        }
    //        i++;
    //}
    return 0;
}

//用来输出切割后的字符串的函数
void debugPrintf(char* argv[])
{
    for(int i = 0; argv[i]; i++)
    {
        printf("%d: %s\n", i, argv[i]);
    }
}

int main()
{
    while(1)
    {
        char commandstr[MAX] = {0};//放在循环内部每次输入后重新创建缓冲区判断
        char* argv[ARGC] = {NULL};//存放切割后的字符串

        printf("[YGH@MyMachina CurrentPath]# ");//命令行的输入是在当前行输入，不能用\n
        fflush(stdout);//不用\n不会行刷新出来，所以要用fflush刷新缓冲区
        char *s = fgets(commandstr, sizeof(commandstr), stdin);//输入的时候最后缓冲区会输入一个\n
        
        assert(s);//断言在debug方式的时候存在，release方式会被裁掉
        (void)s;//这句的用处是让断言在release方式下也不会失效（因为assert被去掉了，s没有被使用会报警，这里用一下就不会报警了）

        commandstr[strlen(commandstr) - 1] = '\0';//去掉我们缓冲区中输入的\n
        
        int n = split(commandstr, argv);//字符串切割
        if(n != 0)//判断字符串是否切割成功
        {
            continue;
        }

        //debugPrintf(argv);//输出切割后的字符串
        pid_t id = fork();
        assert(id >= 0);
        (void)id;

        if(id == 0)
        {
            //子进程
            execvp(argv[0], argv);
            exit(1);//替换失败直接退出
        }
        //父进程
        int status = 0;//退出码
        waitpid(id, &status, 0);//阻塞等待子进程
    }
}